/** @file    WoshKernel.cpp
 *  @author  Alessandro Polo
 *  @version $Id: WoshKernel.cpp 2832 2010-08-02 22:53:46Z alex $
 *  @brief
 * File containing methods for the wosh::WoshKernel class.
 * The header for this class can be found in WoshKernel.h, check that file
 * for class description.
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

 #include <core/WoshKernel.h>
 // modules
 #include <core/ObjectAllocator.h>
 #include <core/ObjectFactory.h>
 #include <core/BundleManager.h>
 #include <core/ThreadManager.h>
 #include <core/UserManager.h>
 #include <core/BusManager.h>
 #include <core/DeviceManager.h>
 #include <core/SecurityManager.h>
 #include <core/PersistenceManager.h>
 #include <core/FileSystem.h>
 #include <core/NetworkManager.h>
 #include <core/SystemMonitor.h>
 #include <core/SystemLogger.h>
 #include <core/SessionManager.h>
 // components
 #include <core/MethodsCommon.h>
 #include <core/MessageProcessingCommon.h>
 #include <core/DataModels.h>
 #include <core/MessageFilter.h>
 #include <core/Notification.h>
 #include <core/Table.h>
 #include <core/Fact.h>
 #include <core/List.h>
 #include <stdio.h>


using namespace std;
namespace wosh {

// Gamma singleton!
extern "C" {
	WoshKernel* ms_WoshKernel_instance = NULL; ///< private reference of static instance
	WoshKernel* WoshKernel::getInstance() { return ms_WoshKernel_instance; }
}

WRESULT WoshKernel::importInstance( WoshKernel* global_instance ) {
	if ( global_instance == NULL ) return WRET_ERR_PARAM;
	if ( ms_WoshKernel_instance != NULL ) return WRET_ERR_ILLEGAL_USE;
	ms_WoshKernel_instance = global_instance;
	return WRET_OK;
 }

 // register as abstract because it is a singleton:
 WOSH_REGISTER_INTERFACE(wosh::WoshKernel, "wosh::Object", 0.01, _static_WoshKernel )

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTORS

WoshKernel::WoshKernel( const string& WoshKernel_name, Settings* settings_default )
	: Object() {
	this->state = WoshKernel::STATE_UNKNOWN;
	if ( settings_default != NULL )		this->SettingsDefault = settings_default;
	else								this->SettingsDefault = new Settings();

	// configure object's info
	if ( WoshKernel_name.size() == 0 )	Object::setName( Utilities::format("wosh%ld", _GET_Abs(Utilities::randomLong())) );
	else								Object::setName( WoshKernel_name );
	Object::getURI().setKernelName(WoshKernel_name);
	Object::getURI().clearPathName();
	Object::getURI().registerGlobal();
	Object::setPermission( Permission( "root", "root", Permission::RWX, Permission::RX, Permission::Read) );

	// configure my own logger
	Log.setIndent( 1 );
	Log.setContext( "WoshKernel" );
	Log.setLevel( LOG_INFO );
Log.setLevel( LOG_VERBOSE );

	Log(LOG_DEBUG, " Initializing.." );
	this->state = WoshKernel::STATE_CREATING;
	this->loopAcquired = false;
	this->stopRequest = false;
	this->listener = NULL;
	ms_WoshKernel_instance = this;

	this->modules = new WoshModule*[_WoshKernel_Modules_SIZE];
	for(int i=0; i<_WoshKernel_Modules_SIZE; i++) { modules[i] = NULL; }
	this->Factory = NULL;
	this->Busses = NULL;
	this->Threads = NULL;
	this->Security = NULL;
	this->Bundles = NULL;
	this->Devices = NULL;
	this->Users = NULL;
	this->Persistence = NULL;
	this->Network = NULL;
	this->FS = NULL;
	this->Monitor = NULL;
	this->SysLog = NULL;
	this->Sessions = NULL;

	Log(LOG_DEBUG, " Setting default properties and permissions.." );
	Properties.set( _KEY_Version,			_WoshKernel_VERSION, Permission(Permission::Read) );
	Properties.set( _WoshModule_KEY_State,	0, Permission( Permission::Read ) );
	Properties.set( _KEY_DebugLevel,		string(LogContext::getLogLevelAsString( Log.getLevel() )), Permission::RW_RW_R__() );
	Properties.set( _KEY_interfaces,		WoshKernel::className(),			Permission(Permission::Read) );
	Properties.set( _WoshKernel_KEY_BuiltRev,			"$Rev $",				Permission(Permission::Read) );
	Properties.set( _WoshKernel_KEY_BuiltDate,			__DATE__" : "__TIME__,	Permission(Permission::Read) );
	Properties.set( _WoshKernel_KEY_BuiltPlatform,		_WOSH_BUILT_PLATFORM,	Permission(Permission::Read) );
	Properties.set( _WoshKernel_KEY_WoshVersionMayor,	_WOSH_VER_MAJOR,		Permission(Permission::Read) );
	Properties.set( _WoshKernel_KEY_WoshVersionMinor,	_WOSH_VER_MINOR,		Permission(Permission::Read) );
	Properties.set( _WoshKernel_KEY_WoshCodeName,		_WOSH_VER_CODENAME,		Permission(Permission::Read) );
	Properties.set( _WoshKernel_KEY_InternalThread,		_THREAD_ARCH,			Permission(Permission::Read) );
	Properties.set( _WoshKernel_KEY_InternalMutex,		_MUTEX_ARCH,			Permission(Permission::Read) );
	Properties.set( _WoshKernel_KEY_StateResumeNext,	true,					Permission::RW_RW_R__() );
 	Properties.monitor( _KEY_DebugLevel );
 	Properties.monitor( _WoshKernel_KEY_StateResumeNext );
	Properties.updateObjectKeys( this );
	Properties.setPermission( Object::getPermission(), Permission::Overwrite_All, true, true );
	Properties.setPropertiesProviderListener(this);

	Log(LOG_VERBOSE, " Using Thread-Arch: " _THREAD_ARCH ", Mutex-Arch:" _MUTEX_ARCH );

	Log(LOG_VERBOSE, " Acquiring ThreadManager.." );
	// can't access to any wosh module!
	this->Threads = &ThreadManager::getInstance();
	this->Threads->setParentObject(this);

	Log(LOG_VERBOSE, " Allocating SystemLogger.." );
	// does almost anything
	this->SysLog = new SystemLogger(this);

	Log(LOG_VERBOSE, " Acquiring ObjectFactory.." );
	// can't access to almost anything!
	this->Factory = &ObjectFactory::getInstance();
	this->Factory->setParentObject(this);

	Log(LOG_VERBOSE, " Allocating SessionManager.." );
	// does almost anything
	this->Sessions = new SessionManager(this);

	Log(LOG_VERBOSE, " Allocating SystemMonitor.." );
	// can't access to the bus!
	this->Monitor = new SystemMonitor(this);

	// since even core-services may access BUS, initialization must be ordered
	Log(LOG_VERBOSE, " Allocating BusManager.." );
	this->Busses = new BusManager(this);

	Log(LOG_VERBOSE, " Allocating FileSystem.." );
	this->FS = new FileSystem(this);

	Log(LOG_VERBOSE, " Allocating SecurityManager.." );
	this->Security = new SecurityManager(this);

	Log(LOG_VERBOSE, " Allocating PersistenceManager.." );
	this->Persistence = new PersistenceManager(this);

	Log(LOG_VERBOSE, " Allocating BundleManager.." );
	this->Bundles = new BundleManager(this);

	Log(LOG_VERBOSE, " Allocating DeviceManager.." );
	this->Devices = new DeviceManager(this);

	Log(LOG_VERBOSE, " Allocating UserManager.." );
	this->Users = new UserManager(this);

	Log(LOG_VERBOSE, " Allocating NetworkManager.." );
	this->Network = new NetworkManager(this);

	int i=0;
	modules[i++] = this->SysLog;
	modules[i++] = this->Threads;
	modules[i++] = this->Factory;
	modules[i++] = this->FS;
	modules[i++] = this->Security;
	modules[i++] = this->Sessions;
	modules[i++] = this->Busses;
	modules[i++] = this->Monitor;
	modules[i++] = this->Network;
	modules[i++] = this->Persistence;

	modules[i++] = this->Users;
	modules[i++] = this->Devices;
	modules[i++] = this->Bundles;

	Log(LOG_DEBUG, " Registering Methods.." );
	Methods.setPermission( Object::getPermission(), Permission::Overwrite_All, true, true );
	Methods.getListPermission().setMask( Permission::Read, Permission::Read, Permission::Read );

	MethodPropertyT::createMethods( &Methods, &Properties, &Log );

	MethodList* mmListMethods = Methods.create<MethodList>( _METHOD_ListMethods, "List Methods", Permission(Permission::RX) );
	mmListMethods->setDataFieldExtractor( DataFieldExtractor<Method>::createFor< DataAdapterMapT<std::string,Method> >(Methods, "WoshKernel Methods") );

	MethodWRESULT* mmShutdown = Methods.create<MethodWRESULT>( _WoshKernel_METHOD_shutdown, "shutdown the system", Permission::R_XR_XR__() );
	mmShutdown->setMethod( this, (MethodWRESULTPtr)&WoshKernel::shutdown );

	MethodRequest* mmListURI = Methods.create<MethodRequest>( _WoshKernel_METHOD_lsuri, "List URIs", Permission::RX );
	mmListURI->setMethod( this->Busses, (MethodRequestPtr)&WoshKernel::mmDoListURI );

	DataAdapterArray<WoshModule>* dataAdapter = new DataAdapterArray<WoshModule>(this->modules, _WoshKernel_Modules_SIZE);
	DataFieldCollector<WoshModule>* fields = WoshModule::getDataFields();
	fields->setDataSetName("Kernel Modules");
	DataFieldExtractor<WoshModule>* dExt = new DataFieldExtractor<WoshModule>(dataAdapter, fields);
	MethodList* mmListMod = Methods.create<MethodList>( _METHOD_List, "List core-modules", Permission(Permission::RX) );
	mmListMod->setDataFieldExtractor(dExt);
//	mmListMod->setDataFieldExtractor( DataFieldExtractor<WoshModule>::createFor(dataAdapter) );

	Variant busType;
	if ( this->SettingsDefault->getSettingsOf("WoshKernel") != NULL )
		busType = this->SettingsDefault->getSettingsOf("WoshKernel")->getValueOf("BusType");
	if ( !busType.isStringNotEmpty() ) busType.set("wosh::BusRing");

	Log(LOG_VERBOSE, " Initializing Bus "_Bus_Core" [%s]..", busType.asString().c_str() );
	WRESULT created_bus = this->Busses->createBus( _Bus_Core, busType.asString() );
	if ( WFAILED(created_bus) )
		Log(LOG_CRITICAL, ": FAILED#%d Registering Bus (wosh.Bus.Core) [%s]..", created_bus, busType.asString().c_str() );
	else {
		BusCore.setMessageHandler(this);
		WRESULT bus_b_connected = BusCore.connect( _Bus_Core );
		if ( WFAILED(bus_b_connected) )
			Log(LOG_CRITICAL, ": FAILED#%d Connecting Bus (wosh.Bus.Core)..", bus_b_connected );
	 }

	Log(LOG_INFO, " WOSH %g.%d [%s] - WoshKernel v.%g $Rev $ " __DATE__ " : " __TIME__"\n",
				_WOSH_VER_MAJOR, _WOSH_VER_MINOR, _WOSH_VER_CODENAME, _WoshKernel_VERSION );
 }

WoshKernel::~WoshKernel() {
	Log(LOG_INFO, " Destroying WoshKernel.." );

	WRESULT destroying = setState(WoshKernel::STATE_DESTROYING, false);
	if ( WFAILED(destroying) )
		Log(LOG_CRITICAL, ":~WoshKernel() : FAILED#%d (pre)Destroying WOSH, see previous logs. But Resuming!..", destroying );
	else
		Log(LOG_INFO, " WOSH (pre)Destroying completed. [DESTROYING]" );

	Log(LOG_VERBOSE, ":~WoshKernel() : Freeing SessionManager.." );
	if ( this->Sessions != NULL )
		delete this->Sessions; this->Sessions = NULL;

	Log(LOG_VERBOSE, ":~WoshKernel() : Freeing BundleManager.." );
	if ( this->Bundles != NULL )
		delete this->Bundles; this->Bundles = NULL;

	Log(LOG_VERBOSE, ":~WoshKernel() : Freeing DeviceManager.." );
	if ( this->Devices != NULL )
		delete this->Devices; this->Devices = NULL;

	Log(LOG_VERBOSE, ":~WoshKernel() : Freeing UserManager.." );
	if ( this->Users != NULL )
		delete this->Users; this->Users = NULL;

	Log(LOG_VERBOSE, ":~WoshKernel() : Freeing SecurityManager.." );
	if ( this->Security != NULL )
		delete this->Security; this->Security = NULL;

	Log(LOG_VERBOSE, ":~WoshKernel() : Freeing PersistenceManager.." );
	if ( this->Persistence != NULL )
		delete this->Persistence; this->Persistence = NULL;

	Log(LOG_VERBOSE, ":~WoshKernel() : Freeing NetworkManager.." );
	if ( this->Network != NULL )
		delete this->Network; this->Network = NULL;

	Log(LOG_VERBOSE, ":~WoshKernel() : Freeing FileSytem.." );
	if ( this->FS != NULL )
		delete this->FS; this->FS = NULL;

	Log(LOG_VERBOSE, ":~WoshKernel() : Freeing BusManager.." );
	if ( this->Busses != NULL )
		delete this->Busses; this->Busses = NULL;

	Log(LOG_VERBOSE, ":~WoshKernel() : Freeing SystemMonitor.." );
	if ( this->Monitor != NULL )
		delete this->Monitor; this->Monitor = NULL;

	Log(LOG_VERBOSE, ":~WoshKernel() : Freeing ObjectFactory.." );
	if ( this->Factory != NULL )
		delete this->Factory; this->Factory = NULL;

	Log(LOG_VERBOSE, ":~WoshKernel() : Freeing SystemLogger.." );
	if ( this->SysLog != NULL )
		delete this->SysLog; this->SysLog = NULL;

	Log(LOG_VERBOSE, ":~WoshKernel() : Freeing ThreadManager.." );
	if ( this->Threads != NULL )
		delete this->Threads; this->Threads = NULL;

	delete [] this->modules;

	if ( this->SettingsDefault != NULL ) {
		Log(LOG_VERBOSE, ":~WoshKernel() : Freeing Settings.." );
		delete this->SettingsDefault; this->SettingsDefault = NULL;
	 }

	Log(LOG_VERBOSE, ":~WoshKernel() : DESTROYED." );
	ms_WoshKernel_instance = NULL;
 }

//////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTORS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////// STATE CONTROL

WRESULT WoshKernel::init() {
	// force the current state again, execute
	// SYNCH call to WoshModule::onKernelInitializing();
	// also broadcast kernel-state event
	WRESULT initializing = setState(WoshKernel::STATE_INITIALIZING, true);
	if ( WFAILED(initializing) ) {
		bool ignoreErrors = Properties.getValueOf(_WoshKernel_KEY_StateResumeNext).toBoolean(false);
		if ( !ignoreErrors ) {
			Log(LOG_CRITICAL, ":init() FAILED#%d : (pre)Initializing WOSH, see previous logs.", initializing );
			return initializing;
		 }
		else
			Log(LOG_CRITICAL, ":init() FAILED#%d : (pre)Initializing WOSH, see previous logs. But Resuming!..", initializing );
	 }
	else
		Log(LOG_VERBOSE, ":init() : WOSH (pre)Initializing completed. [INITIALIZING]" );

	// notify that.. all modules (hopefully) are initialized.
	// it's a sort of post initialization to eventually resolve
	// init conflicts between modules
	WRESULT initialized = setState(WoshKernel::STATE_INITIALIZED, true);
	if ( WFAILED(initialized) )
		Log(LOG_CRITICAL, ":init() FAILED#%d : (post)Initializing WOSH, see previous logs.", initialized );
	else
		Log(LOG_INFO, ":init() : WOSH (post)Initializing completed. [INITIALIZED]" );

	return initializing+initialized;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT WoshKernel::start() {
	WRESULT started = setState(WoshKernel::STATE_RUNNING, true);
	if ( WFAILED(started) )
		Log(LOG_CRITICAL, ":start() FAILED#%d : (pre)Initializing WOSH, see previous logs.", started );
	else
		Log(LOG_INFO, ":start() : WOSH is now running." );

	return started;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT WoshKernel::shutdown() {
	if ( this->state == WoshKernel::STATE_STOPPED ) {
		Log(LOG_CRITICAL, ":shutdown() FAILED#%d : Already in STOPPED state!", WRET_ERR_ILLEGAL_USE );
		return WRET_ERR_ILLEGAL_USE;
	 }
	if ( this->state == WoshKernel::STATE_STOPPING ) {
		// then it's another thread asking to stop..
		Log(LOG_WARNING, ":shutdown() FAILED#%d : Already stopping..", WRET_ERR_ILLEGAL_USE );
		Log(LOG_DEBUG, ":shutdown() : Forcing stopRequest=true" );
		this->stopRequest = true;
		return WRET_ERR_ILLEGAL_USE;
	 }
	if ( this->loopAcquired ) {
		// then it's another thread asking to stop.. then break the loop
		Log(LOG_DEBUG, ":shutdown() : Forcing stopRequest=true" );
		this->stopRequest = true;
		// so stopping is asych
		return WRET_OK;
	 }
	// synch stop
	// SYNCH call to WoshModule::onKernelStopping();
	// also broadcast kernel-state event
	WRESULT stopping = setState(WoshKernel::STATE_STOPPING, true);
	if ( WFAILED(stopping) ) {
		bool ignoreErrors = Properties.getValueOf(_WoshKernel_KEY_StateResumeNext).toBoolean(false);
		if ( !ignoreErrors ) {
			Log(LOG_CRITICAL, ":shutdown() FAILED#%d : (pre)DeInitializing WOSH, see previous logs.", stopping );
			return stopping;
		 }
		else
			Log(LOG_CRITICAL, ":shutdown() FAILED#%d : (pre)DeInitializing WOSH, see previous logs. But Resuming!..", stopping );
	 }
	else
		Log(LOG_INFO, ":shutdown() WOSH (pre)DeInitializing completed. [STOPPING]" );

	// notify that.. all modules (hopefully) are deinitialized.
	// it's a sort of post deinitialization to eventually resolve
	// init conflicts between modules
	WRESULT stopped = setState(WoshKernel::STATE_STOPPED, false);
	if ( WFAILED(stopped) )
		Log(LOG_CRITICAL, ":shutdown() FAILED#%d : (post)DeInitializing WOSH, see previous logs.", stopped );
	else
		Log(LOG_INFO, ":shutdown() WOSH (post)DeInitializing completed. [STOPPED]" );

	return stopping+stopped;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT WoshKernel::enterLoop() {
	if ( this->state != WoshKernel::STATE_RUNNING ) {
		Log(LOG_CRITICAL, ":enterLoop() : FAILED: Not in RUNNING state!" );
		return WRET_ERR_ILLEGAL_USE;
	 }
	Log(LOG_INFO, ":enterLoop() : Aquired (main) Thread!" );
	this->loopAcquired = true;
	while( !this->stopRequest ) {
		ThreadImpl::sleepForMSec(500);
	 }
	this->loopAcquired = false;
	Log(LOG_INFO, ":enterLoop() : Stopping and Leaving Thread!" );
	return shutdown();

 }

/////////////////////////////////////////////////////////////////////////////////////////////// STATE CONTROL
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////// PROCESS BUS MESSAGES

void WoshKernel::busMessage( const Message& message, const Bus* ) {
	if ( message.isEmpty() || !message.getContent()->isRequest() ) return;
	if ( !MessageFilter::isMessageTarget(message, this) ) return;
	// similar to BundleGeneric, common implementation in MessageProcessingCommon.cpp
	Message* reply = MPC_busMessageRequest( message, Methods, Log );
	if ( reply == NULL ) return;
	reply->setSource(this);
	BusCore.postMessage(reply);
 }

//////////////////////////////////////////////////////////////////////////////////////// PROCESS BUS MESSAGES
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////// PROPERTY EVENTS

bool WoshKernel::updatingProperty( bool& , const Variant& value_proposed, Property& property_current, const PropertiesProvider* ) {
	if ( property_current.getKey() == _KEY_DebugLevel )
		return MPC_PropertyParse_LogLevel( value_proposed, this->Log );
	// not handled, sound strange but probably its ok since we are the lower (base) implementation
	return true;
 }

///////////////////////////////////////////////////////////////////////////////////////////// PROPERTY EVENTS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

Response* WoshKernel::mmDoListURI( const Request* request ) {
	if ( request == NULL ) return NULL;
	
	List* obj_list = new List();
	URI temp("*:**");
	URICollector::getInstance().list( &temp, true, obj_list->getVector() );

	///@todo implement here
	return request->replyResponse(WRET_OK, obj_list);
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT WoshKernel::setState( WoshKernel::KERNEL_STATE new_state, bool raise_event ) {
	WoshKernel::KERNEL_STATE old_state = this->state;
	if ( _GET_Abs(static_cast<int>(new_state) - static_cast<int>(old_state)) != 1 ) {
		Log(LOG_CRITICAL, ":setState(%s) : KERNEL-FAILURE [can't switch from %s]", getStateAsString(new_state), getStateAsString(old_state) );
		return WRET_ERR_ILLEGAL_USE;
	 }
	WRESULT ret = WRET_OK; WRESULT ret_t = WRET_OK;
	Log(LOG_VERBOSE, ":setState() : Switching state %s => %s..", getStateAsString(old_state), getStateAsString(new_state) );
	int errors = 0;
	for(int i=0; i<_WoshKernel_Modules_SIZE; i++) {
		if ( modules[i] == NULL ) continue;
		ret_t = modules[i]->kernel_StateChanged( static_cast<int>(new_state), static_cast<int>(old_state) );
		if ( WFAILED(ret_t) ) {
			Log(LOG_WARNING, ":setState(%s) : Module[%d] '%s' ERROR#%d", getStateAsString(new_state), i, modules[i]->getName().c_str(), ret_t );
			++errors;
		 }
		ret += ret_t;
	 }
	if ( WFAILED(ret) ) {
		bool ignoreErrors = Properties.getValueOf(_WoshKernel_KEY_StateResumeNext).toBoolean(false);
		if ( !ignoreErrors ) {
			Log(LOG_CRITICAL, ":setState(%s => %s) : KERNEL-FAILURE [%d Module(s) ERRORs#%d]", getStateAsString(old_state), getStateAsString(new_state), errors, ret );
			return ret;
		 }
		Log(LOG_WARNING, ":setState(%s => %s) : Ignoring %d Module(s) ERRORs#%d", getStateAsString(old_state), getStateAsString(new_state), errors, ret );
	 }
	if ( this->listener != NULL )
		this->listener->kernel_StateChanged( old_state, new_state, this );

	Log(LOG_INFO, " Applied State %s ", getStateAsString(new_state) );
	this->state = new_state;
	Properties.transactionBeginWrite();
	Properties.update( _WoshKernel_KEY_State, getStateAsString(new_state) );
	Properties.transactionEnd();

	if ( !raise_event ) return ret;
	Message* msg_event = new Message( new WoshKernel_StateChanged(new_state, old_state) );
	msg_event->setDestinationBroadcast(true);
	msg_event->setSource(this);
	SecurityManager::getCredentialImplicit().signMessage(msg_event, this);
	BusCore.postMessage(msg_event);
	return ret;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////// STATIC

const char* WoshKernel::getKernelName() {
	if ( WoshKernel::getInstance() == NULL )
		return "";
	return WoshKernel::getInstance()->getName().c_str();
 }

WoshKernel::KERNEL_STATE WoshKernel::getKernelState() {
	if ( WoshKernel::getInstance() == NULL )
		return WoshKernel::STATE_FAILURE;
	return WoshKernel::getInstance()->getState();
 }

const char* WoshKernelStateStr[] = {
	"UNKNOWN",		///< (KERNEL_STATE)0
	"CREATING",		///< (KERNEL_STATE)1
	"INITIALIZING",	///< (KERNEL_STATE)2
	"INITIALIZED",	///< (KERNEL_STATE)3
	"RUNNING",		///< (KERNEL_STATE)4
	"STOPPING",		///< (KERNEL_STATE)5
	"STOPPED",		///< (KERNEL_STATE)6
	"DESTROYING",	///< (KERNEL_STATE)7
	"",				///< (KERNEL_STATE)8
	"FAILURE"		///< (KERNEL_STATE)9
};

Enum2StrFromArray(WoshKernel::getStateAsString, WoshKernel::KERNEL_STATE, STATE_INITIALIZING, STATE_FAILURE, 0, WoshKernelStateStr)

Str2EnumByArray(WoshKernel::getStateFromString, WoshKernel::KERNEL_STATE, 0, STATE_FAILURE, STATE_UNKNOWN, WoshKernelStateStr)

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WoshKernel::KERNEL_STATE intToWoshKernelStateEnum( int value ) {
	if ( value <= WoshKernel::STATE_UNKNOWN ) return WoshKernel::STATE_UNKNOWN;
	if ( value > WoshKernel::STATE_FAILURE ) return WoshKernel::STATE_UNKNOWN;
	return (WoshKernel::KERNEL_STATE)value;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

 WOSH_REGISTER(wosh::WoshKernel_StateChanged, "wosh::Fact", 1.0, _static_WoshKernel_StateChanged )

WoshKernel_StateChanged::WoshKernel_StateChanged( WoshKernel::KERNEL_STATE new_state )
	: Fact( _WoshKernel_EVENT_StateChanged ) {
	setData( new Variant( (int)new_state ) );
 }

WoshKernel_StateChanged::WoshKernel_StateChanged( WoshKernel::KERNEL_STATE new_state, WoshKernel::KERNEL_STATE old_state )
	: Fact( _WoshKernel_EVENT_StateChanged ) {
	List* args = List::createFrom<Variant>( (int)new_state, (int)old_state );
	setData(args);
 }

WoshKernel::KERNEL_STATE WoshKernel_StateChanged::getState() const {
	if ( !hasData() ) return WoshKernel::STATE_UNKNOWN;
	if ( content->isKindOf<Variant>() ) {
		const Variant* val = content->as<Variant>();
		if ( val == NULL ) return WoshKernel::STATE_UNKNOWN;
		return intToWoshKernelStateEnum(val->toInteger((int)WoshKernel::STATE_UNKNOWN));
	 }
	if ( getData()->isKindOf<List>() ) {
		const List* list = getData()->as<List>();
		if ( list == NULL ) return WoshKernel::STATE_UNKNOWN;
		if ( list->size() < 1 ) return WoshKernel::STATE_UNKNOWN;
		if ( list->itemAt(0) == NULL ) return WoshKernel::STATE_UNKNOWN;
		const Variant* val = list->itemAt(0)->as<Variant>();
		if ( val == NULL ) return WoshKernel::STATE_UNKNOWN;
		if ( !val->isNumeric() ) return WoshKernel::STATE_UNKNOWN;
		return intToWoshKernelStateEnum(val->toInteger((int)WoshKernel::STATE_UNKNOWN));
	 }
	return WoshKernel::STATE_UNKNOWN;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

}; // namespace wosh
